<template>
    <div>
        <div>
            <div style="width: 200px;">
                <vue-slider :min="20" :max="200" v-model="value"></vue-slider>
            </div>
            <div>
                <button @click="handlerImageRotate(-90)">
                    -90°
                </button>
                <button @click="handlerImageRotate(90)">
                    90°
                </button>
            </div>
            <div>
                <button @click="handleCropImage">
                    crop
                </button>
            </div>
        </div>

        <div class="editor-container" ref="container">
            <div class="editor-position">
                <div id="konva--body" ref="body" :style="bodyStyles"></div>
            </div>

        </div>

    </div>
</template>

<script>
    import Konva                         from 'konva';
    import VueSlider                     from 'vue-slider-component'
    import 'vue-slider-component/theme/default.css'
    import { asyncImageLoader, cloneOf } from "../Utilys/methods";

    const DRAG_ATTRIBUTE_DEFAULT_OBEJECT = {
        active  : false,
        currentX: null,
        currentY: null,
        initialX: null,
        initialY: null,
        xOffset : 0,
        yOffset : 0,
    };

    export default {
        name      : "konva-editor",
        components: {
            VueSlider
        },
        data() {
            return {
                stageObj    : {
                    obj   : null,
                    height: null,
                    width : null,
                    rotate: 0,
                },
                imageObj    : {
                    obj    : null,
                    element: null,
                    height : null,
                    width  : null,
                },
                layerObj    : {
                    obj: null,
                },
                transformObj: {
                    x: 0,
                    y: 0,
                    z: 1,
                },
                cropObj     : {
                    active: false,
                    obj   : null,
                },

                historyList: [],
                dragObj    : cloneOf(DRAG_ATTRIBUTE_DEFAULT_OBEJECT),
                value      : 100,
            };
        },
        computed  : {
            bodyStyles() {
                let { x, y, z } = this.transformObj;
                return {
                    transform: `translate(${ x }px , ${ y }px) scale(${ z })`
                }
            }
        },
        mounted() {
            this.start("/images/test1.jpg");
            this.bodyDragEvent();
        },
        methods   : {
            handleCropImage() {
                this.cropObj.active = !this.cropObj.active;

                this.cropObj.active ? this.mapToMakeCropImage() : this.mapToRemoveCropImage();
            },
            mapToMakeCropImage() {
                let { obj: layer }        = this.layerObj;
                let { group: imageGroup } = this.imageObj;
                let { width, height }     = this.stageObj;
                let group                 = new Konva.Group();

                let make = new Konva.Rect({
                    width,
                    height,
                    fill: 'rgba(0,0,0,0.5)',
                });

                group.add(make);

                let fakeShape = new Konva.Rect({
                    width    : 100,
                    height   : 100,
                    x        : 100,
                    y        : 100,
                    fill     : 'black',
                    draggable: true,
                });

                // var tr = new Konva.Transformer({
                //     node: fakeShape
                // });
                group.add(fakeShape);
                group.globalCompositeOperation("destination-out");

                // group.globalCompositeOperation("destination-over");

                layer.add(group);

                layer.draw();
            },
            mapToRemoveCropImage() {
                let { obj: crop } = this.cropObj;
                if (crop) crop.remove();
            },
            handlerImageRotate(d) {
                let { obj: stage }          = this.stageObj;
                this.stageObj.rotate += d;
                let { obj: image, element } = this.imageObj;
                let canvas                  = this.drawRotated(d, element);
                this.historyList.push({
                    type: 'rotate',
                    data: {
                        rotateDegress: d,
                        beforeImage  : element,
                        afterImage   : canvas,
                    },
                });
                this.imageObj.element = canvas;

                let { width, height } = canvas;

                let size = this.stageSize(width, height);
                console.log('size :', size);


                stage.width(size.width);
                stage.height(size.height);

                image.width(size.width);
                image.height(size.height);
                stage.offsetX(size.width / 2);
                stage.offsetY(size.height / 2);
                stage.y(size.height / 2);
                stage.x(size.width / 2);

                this.value = 100;

                image.image(canvas);
                // stage.rotate(d);
                stage.batchDraw();

            },
            async start(url) {

                await this.mapToLoadImageElement(url);
                this.mapToMakeStage();
                this.mapToMakeLayer();
                this.mapToLoadImageObj();
                this.layerObj.obj.draw();
            },
            bodyDragEvent() {
                let { body } = this.$refs;
                body.addEventListener("touchstart", this.dragStart.bind(this), false);
                body.addEventListener("touchend", this.dragEnd.bind(this), false);
                body.addEventListener("touchmove", this.drag.bind(this), false);

                body.addEventListener("mousedown", this.dragStart.bind(this), false);
                body.addEventListener("mouseup", this.dragEnd.bind(this), false);
                body.addEventListener("mousemove", this.drag.bind(this), false);
            },
            async mapToLoadImageElement(url) {
                let image = await asyncImageLoader(url);

                this.imageObj.element = image;
                this.imageObj.height  = image.height;
                this.imageObj.width   = image.width;
            },
            mapToMakeStage() {
                let { obj }           = this.stageObj;
                let { width, height } = this.imageObj;
                let size              = this.stageSize(width, height);
                if (obj) obj.remove();

                let stage = new Konva.Stage({
                    container: 'konva--body',
                    width    : size.width,
                    height   : size.height,
                });

                stage.on('dragstart', (e) => {
                    console.log('e :', e);
                    // this.dragStart()
                });

                this.stageObj.obj = stage;
            },
            mapToMakeLayer() {
                let { obj: stage } = this.stageObj;

                const layer = new Konva.Layer();
                stage.add(layer);

                this.layerObj.obj = layer;
            },
            mapToLoadImageObj() {
                let { element }       = this.imageObj;
                let { width, height } = this.stageObj;
                const group           = new Konva.Group();
                const image           = new Konva.Image({
                    image: element,
                    width,
                    height,
                });


                group.add(image);
                this.layerObj.obj.add(group);

                this.imageObj.group = group;
                this.imageObj.obj   = image;

            },
            stageSize(width, height) {
                let { container }                 = this.$refs;
                let { offsetHeight, offsetWidth } = container;

                if (!(width < offsetWidth && height < offsetHeight)) {
                    if (offsetWidth / offsetHeight <= width / height) //原图片宽高比例 大于 图片框宽高比例
                    {
                        width  = (offsetWidth * 0.8);   //以框的宽度为标准
                        height = (offsetWidth * 0.8) * (height / width);
                    } else {   //原图片宽高比例 小于 图片框宽高比例
                        width  = (offsetHeight * 0.8) * (width / height);
                        height = offsetHeight * 0.8;   //以框的高度为标准
                    }
                }

                this.stageObj.height = height;
                this.stageObj.width  = width;
                return {
                    width,
                    height
                }

            },
            dragStart(e) {
                if (this.cropObj.active)
                    return;
                if (e.type === "touchstart") {
                    this.dragObj.initialX = e.touches[ 0 ].clientX - this.dragObj.xOffset;
                    this.dragObj.initialY = e.touches[ 0 ].clientY - this.dragObj.yOffset;
                } else {
                    this.dragObj.initialX = e.clientX - this.dragObj.xOffset;
                    this.dragObj.initialY = e.clientY - this.dragObj.yOffset;
                }

                // console.log('e :', e.target);
                this.active = true;
            },
            dragEnd(e) {
                this.dragObj.initialX = this.dragObj.currentX;
                this.dragObj.initialY = this.dragObj.currentY;

                this.active = false;
            },
            drag(e) {
                if (this.active) {

                    e.preventDefault();

                    if (e.type === "touchmove") {
                        this.dragObj.currentX = e.touches[ 0 ].clientX - this.dragObj.initialX;
                        this.dragObj.currentY = e.touches[ 0 ].clientY - this.dragObj.initialY;
                    } else {
                        this.dragObj.currentX = e.clientX - this.dragObj.initialX;
                        this.dragObj.currentY = e.clientY - this.dragObj.initialY;
                    }

                    this.dragObj.xOffset = this.dragObj.currentX;
                    this.dragObj.yOffset = this.dragObj.currentY;
                    this.transformObj.x  = this.dragObj.currentX || 0;
                    this.transformObj.y  = this.dragObj.currentY || 0;
                }
            },
            resetDrag() {
                this.$set(this, 'dragObj', cloneOf(DRAG_ATTRIBUTE_DEFAULT_OBEJECT));
            },
            setTransformZ(val) {
                this.transformObj = {
                    x: 0,
                    y: 0,
                    z: val
                }
            },
            drawRotated(degrees, image) {
                var canvas = document.createElement("canvas");
                var ctx    = canvas.getContext("2d");
                console.log('degrees :', degrees);
                canvas.width  = image.height;
                canvas.height = image.width;

                ctx.clearRect(0, 0, canvas.width, canvas.height);
                ctx.translate(image.height / 2, image.width / 2);

                ctx.rotate(degrees * Math.PI / 180);
                ctx.drawImage(image, -image.width / 2, -image.height / 2);
                return canvas;
            },
        },
        watch     : {
            value(value) {
                console.log('value :', value);
                this.resetDrag();
                this.setTransformZ(value / 100)
            }
        }
    }
</script>

<style scoped lang="less">

    .editor-container {
        position: relative;
        width: 100%;
        height: 700px;
        background-color: #000;
        overflow: hidden;
    }

    .editor-position {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }

</style>
